﻿using Dapper;
using Loong.Domain.Uow;
using Loong.Threading.Locks.Database;
using Microsoft.Extensions.Options;
using MySql.Data.MySqlClient;
using System.Data;
using System.Threading.Tasks;

namespace Loong.Threading.Locks
{
    public class ResourceLockDbAccessor : IResourceLockDbAccessor
    {
        private readonly ConnectionStringOptions _options;

        public ResourceLockDbAccessor(IOptionsMonitor<ConnectionStringOptions> options)
        {
            _options = options.CurrentValue;
        }

        public async Task<ResourceLock> GetByResourceAsync(string resource)
        {
            string sql = "SELECT * FROM ResourceLock WHERE `Resource`=@resource";

            using (var connection = new MySqlConnection(_options.DefaultConnection))
            {
                connection.Open();
                using (var transaction = await connection.BeginTransactionAsync(IsolationLevel.ReadCommitted))
                {
                    ResourceLock resourceLock = await connection.QueryFirstOrDefaultAsync<ResourceLock>(sql, new { resource }, transaction);

                    await transaction.CommitAsync();
                    await connection.CloseAsync();

                    return resourceLock;
                }
            }
        }

        public async Task InsertAsync(ResourceLock resourceLock)
        {
            string sql = @"
INSERT INTO ResourceLock
(
`Resource`,
`ExpireTime`,
`Version`,
`LockOwner`
)VALUES(
@Resource,
@ExpireTime,
@Version,
@LockOwner
)
";

            using (var connection = new MySqlConnection(_options.DefaultConnection))
            {
                connection.Open();
                using (var transaction = await connection.BeginTransactionAsync(IsolationLevel.ReadCommitted))
                {
                    await connection.ExecuteAsync(sql, resourceLock, transaction);

                    await transaction.CommitAsync();
                    await connection.CloseAsync();
                }
            }
        }

        public async Task<bool> UpdateLockAsync(ResourceLock resourceLock)
        {
            string sql = @"
UPDATE ResourceLock SET
`ExpireTime`=@ExpireTime,
`Version`=`Version`+1,
`LockOwner`=@LockOwner
WHERE `Id`=@Id AND `Version`=@Version
";
            using (var connection = new MySqlConnection(_options.DefaultConnection))
            {
                connection.Open();
                using (var transaction = await connection.BeginTransactionAsync(IsolationLevel.ReadCommitted))
                {
                    bool sucess = await connection.ExecuteAsync(sql, resourceLock, transaction) == 1;

                    await transaction.CommitAsync();
                    await connection.CloseAsync();

                    return sucess;
                }
            }
        }

        public bool ReleaseLock(string resource, string lockOwner)
        {
            string sql = "DELETE FROM ResourceLock WHERE `Resource`=@resource AND `LockOwner`=@lockOwner";

            using (var connection = new MySqlConnection(_options.DefaultConnection))
            {
                connection.Open();
                using (var transaction = connection.BeginTransaction())
                {
                    bool success = connection.Execute(sql, new { resource, lockOwner }, transaction) == 1;

                    transaction.Commit();
                    connection.Close();

                    return success;
                }
            }
        }
    }
}
